using System;
using MLSharp.Classification;
using MLSharp.Utilities;

namespace MLSharp.Evaluation
{
	/// <summary>
	/// A result writer that streams results to a CSV file.
	/// </summary>
	public class CsvResultWriter : IFileResultWriter, IDisposable
	{
		/// <summary>
		/// The logger for the class.
		/// </summary>
		private static log4net.ILog mLogger =
			log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

		/// <summary>
		/// The underlying CsvWriter that the results are written to.
		/// </summary>
		private CsvWriter mWriter;

		/// <summary>
		/// The name of the file being written to.
		/// </summary>
		public string OutputFileName { get; set; }

		/// <summary>
		/// Creates a writer that isn't bound to a filename.  This constructor
		/// is provided to support dynamic loading.
		/// </summary>
		public CsvResultWriter()
		{
			
		}

		/// <summary>
		/// Creates a writer for the specified filename.
		/// </summary>
		/// <param name="filename"></param>
		public CsvResultWriter(string filename)
		{
			OutputFileName = filename;
		}

		/// <summary>
		/// Writes the specified results to a file.
		/// </summary>
		/// <param name="dataSet">Unused.</param>
		/// <param name="classificationResults"></param>
		public void ProcessResults(IDataSet dataSet, ClassificationResult[] classificationResults)
		{
			//Write the header
			mWriter.WriteRow("\"ID\"", dataSet.Attributes[dataSet.TargetAttributeIndex].Name, "Predicted", "Confidence", "Explanation");

			foreach (ClassificationResult result in classificationResults)
			{
				mWriter.WriteRow(result.ID, result.ActualClass, result.PredictedClass, result.Confidence, result.Explanation);
			}
		}

		/// <summary>
		/// When called, the writer should initialize/re-initialize.
		/// This is provided so that a single result writer can be used
		/// multiple times.
		/// </summary>
		public void Initialize()
		{
			if (mWriter != null)
			{
				throw new InvalidOperationException("Can't initialize an already initialized writer without first calling Close.");
			}

			mWriter = new CsvWriter(OutputFileName);

			mLogger.Debug("Writing output to " + OutputFileName);
		}

		/// <summary>
		/// Closes the writer. 
		/// </summary>
		public void Close()
		{
			if (mWriter == null)
			{
				throw new InvalidOperationException("Writer is already closed, call Initialize first.");
			}

			mWriter.Dispose();
			mWriter = null;
		}

		/// <summary>
		/// Cleans up the writer.
		/// </summary>
		void IDisposable.Dispose()
		{
			if (mWriter != null)
			{
				Close();
			}
		}
	}
}